﻿#region Copyright(C) 2010-2012 FI Ltd. All rights reserved.
// ==================================================================================================
// Copyright(C) 2018 FI Ltd. All rights reserved.
//
// SYSTEM NAME	    : FI.Net Application Framework
// COMPONENT ID	    : FI.Core.StringResource.StringRecord
// COMPONENT DESC   : 
//
// CREATED DATE/BY  : 18 Aug 2018 / Tian Mi
//
// REVISION HISTORY : 
// DATE/BY			SR#/CS/PM#/OTHERS		DESCRIPTION OF CHANGE
// ==================================================================================================
#endregion

using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization;
using FI.Core;
using FI.Core.Utilities;

namespace FI.Core.StringResource
{
    /// <summary>
    /// String Record
    /// </summary>
    [DebuggerDisplay("Current : {Category} {Culture} {Name} {Value} , ({OrginalCategory} {OrginalCulture} {OrginalName} {OrginalValue})")]
    [DataContract(Namespace = Constants.Namespace)]
    public class StringRecord
    {
        [DataMember]
        private string category;
        [DataMember]
        private string culture;
        [DataMember]
        private string name;
        [DataMember]
        private string value;
        [DataMember]
        private RecordState recordState;

        [DataMember]
        private string originalCategory;
        [DataMember]
        private string originalCulture;
        [DataMember]
        private string originalName;
        [DataMember]
        private string originalValue;
        [DataMember]
        private RecordState orginalRecordState;

        /// <summary>
        /// Gets or sets the category.
        /// </summary>
        /// <value>
        /// The category.
        /// </value>
        public string Category
        {
            get { return category; }
            set
            {
                category = value;
                MarkValueModified();
            }
        }
        /// <summary>
        /// Gets or sets the culture.
        /// </summary>
        /// <value>
        /// The culture.
        /// </value>
        public string Culture
        {
            get { return culture; }
            set
            {
                culture = value;
                MarkValueModified();
            }
        }
        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>
        /// The name.
        /// </value>
        public string Name
        {
            get { return name; }
            set
            {
                name = value;
                MarkValueModified();
            }
        }
        /// <summary>
        /// Gets or sets the value.
        /// </summary>
        /// <value>
        /// The value.
        /// </value>
        public string Value
        {
            get { return value; }
            set
            {
                this.value = value;
                MarkValueModified();
            }
        }
        /// <summary>
        /// Gets the state of the record.
        /// </summary>
        /// <value>
        /// The state of the record.
        /// </value>
        public RecordState RecordState
        {
            get { return recordState; }
        }

        /// <summary>
        /// Gets or sets the orginal category.
        /// </summary>
        /// <value>
        /// The orginal category.
        /// </value>
        public string OriginalCategory
        {
            get { return originalCategory; }
            set { originalCategory = value; }
        }
        /// <summary>
        /// Gets or sets the orginal culture.
        /// </summary>
        /// <value>
        /// The orginal culture.
        /// </value>
        public string OriginalCulture
        {
            get { return originalCulture; }
            set { originalCulture = value; }
        }
        /// <summary>
        /// Gets or sets the name of the orginal.
        /// </summary>
        /// <value>
        /// The name of the orginal.
        /// </value>
        public string OriginalName
        {
            get { return originalName; }
            set { originalName = value; }
        }
        /// <summary>
        /// Gets or sets the orginal value.
        /// </summary>
        /// <value>
        /// The orginal value.
        /// </value>
        public string OriginalValue
        {
            get { return originalValue; }
            set { originalValue = value; }
        }
        /// <summary>
        /// Gets the state of the orginal record.
        /// </summary>
        /// <value>
        /// The state of the orginal record.
        /// </value>
        public RecordState OriginalRecordState
        {
            get { return orginalRecordState; }
        }

        /// <summary>
        /// Gets the string record set.
        /// </summary>
        public StringRecordSet StringRecordSet { get; internal set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="StringRecord"/> class.
        /// </summary>
        /// <param name="category">The category.</param>
        /// <param name="culture">The culture name.</param>
        /// <param name="name">The name.</param>
        /// <param name="value">The value.</param>
        public StringRecord(string category, string culture, string name, string value)
            : this(category, new CultureInfo(culture), name, value)
        {
        }


        /// <summary>
        /// Initializes a new instance of the <see cref="StringRecord"/> class.
        /// </summary>
        /// <param name="category">The category.</param>
        /// <param name="culture">The culture.</param>
        /// <param name="name">The name.</param>
        /// <param name="value">The value.</param>
        public StringRecord(string category, CultureInfo culture, string name, string value)
        {
            Guard.ArgumentNotNull(category, "category");
            Guard.ArgumentNotNull(culture, "culture");
            Guard.ArgumentNotNull(name, "name");
            Guard.ArgumentNotNull(value, "value");

            this.category = category;
            this.culture = culture.Name;
            this.name = name;
            this.value = value;

            recordState = RecordState.Detached;

            SaveNewOrginal();
        }


        /// <summary>
        /// Marks the value modified.
        /// </summary>
        private void MarkValueModified()
        {
            if(recordState == RecordState.Unchanged)
            {
                recordState = RecordState.Modified;
            }
        }

        /// <summary>
        /// Saves the new orginal status.
        /// </summary>
        private void SaveNewOrginal()
        {
            originalCategory = category;
            originalCulture = culture;
            originalName = name;
            originalValue = value;
            orginalRecordState = recordState;
        }

        /// <summary>
        /// Marks the string record added.
        /// </summary>
        internal void MarkStringRecordAdded()
        {
            if(recordState == RecordState.Detached)
            {
                recordState = RecordState.Added;
            }
        }

        /// <summary>
        /// Marks the string record removed.
        /// </summary>
        internal void MarkStringRecordRemoved()
        {
            if (recordState == RecordState.Added)
            {
                recordState = RecordState.Detached;
                return;
            }
            if(recordState == RecordState.Modified || recordState == RecordState.Unchanged)
            {
                recordState = RecordState.Deleted;
                return;
            }
        }

        /// <summary>
        /// Accepts the changes.
        /// </summary>
        internal void AcceptChanges()
        {
            if (recordState == RecordState.Modified || recordState == RecordState.Added)
            {
                recordState = RecordState.Unchanged;
                SaveNewOrginal();
                return;
            }
            if (recordState == RecordState.Deleted)
            {
                recordState = RecordState.Detached;
                return;
            }
        }

        /// <summary>
        /// Rejects the changes.
        /// </summary>
        internal void RejectChanges()
        {
            if(recordState == RecordState.Added)
            {
                Rollback();
                StringRecordSet.Remove(this);
                return;
            }
            if(recordState == RecordState.Modified)
            {
                Rollback();
                return;
            }
            if(recordState == RecordState.Deleted)
            {
                recordState = RecordState.Unchanged;
                return;
            }
        }

        /// <summary>
        /// Rollbacks the changes to orignal status.
        /// </summary>
        internal void Rollback()
        {
            category = originalCategory;
            culture = originalCulture;
            name = originalName;
            value = originalValue;
            recordState = orginalRecordState;
        }

        /// <summary>
        /// Deletes this record.
        /// </summary>
        public void Delete()
        {
            if(recordState == RecordState.Added || recordState == RecordState.Modified || recordState == RecordState.Unchanged)
            {
                StringRecordSet.Remove(this);
            }
        }
    }
}
